package com.easylinkin.linkappapi.jglplant.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.easylinkin.linkappapi.common.exceptions.BusinessException;
import com.easylinkin.linkappapi.common.service.CommonService;
import com.easylinkin.linkappapi.common.utils.excel.ExcelConstant;
import com.easylinkin.linkappapi.common.utils.excel.ExcelTools;
import com.easylinkin.linkappapi.common.utils.io.OutputStreamUtil;
import com.easylinkin.linkappapi.jglplant.dao.JglPlantDao;
import com.easylinkin.linkappapi.jglplant.dao.JglPlantRefExpertDao;
import com.easylinkin.linkappapi.jglplant.entity.*;
import com.easylinkin.linkappapi.jglplant.service.JglExpertService;
import com.easylinkin.linkappapi.jglplant.service.JglPlantRefExpertService;
import com.easylinkin.linkappapi.jglplant.service.JglPlantService;
import com.easylinkin.linkappapi.security.context.LinkappUserContextProducer;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.OutputStream;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;

/**
 * 鸡公岭-植物库(JglPlant)表服务实现类
 *
 * @author makejava
 * @since 2022-02-18 17:47:20
 */
@Service
public class JglPlantServiceImpl extends ServiceImpl<JglPlantDao, JglPlant> implements JglPlantService {
    @Resource
    private LinkappUserContextProducer linkappUserContextProducer;
    @Resource
    private CommonService commonService;
    @Resource
    private JglPlantRefExpertDao jglPlantRefExpertDao;
    @Resource
    private JglPlantRefExpertService jglPlantRefExpertService;
    @Resource
    private JglExpertService jglExpertService;


    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean saveOne(JglPlant jglPlant) {
        commonService.setCreateAndModifyInfo(jglPlant);
        jglPlant.setTenantId(linkappUserContextProducer.getNotNullCurrent().getTenantId());
        validParamRequired(jglPlant);
        validRepeat(jglPlant);
        validParamFormat(jglPlant);
        boolean r = save(jglPlant);
        updateExpertResearchAreaAndUpdatePlantRefExpert(jglPlant);
        return r;
    }

    /**
     * 更新专家的擅长领域 以及 更新植物与专家的关联关系
     *
     * @param jglPlant vo
     */
    private void updateExpertResearchAreaAndUpdatePlantRefExpert(JglPlant jglPlant) {
        List<JglExpert> jglExpertList = jglPlant.getJglExpertList();
        List<JglPlantRefExpert> jglPlantRefExpertList = new LinkedList<>();
        if (jglExpertList != null) {
            for (JglExpert jglExpert : jglExpertList) {
                Assert.notNull(jglExpert.getId(), "专家列表参数中id为空");
                JglExpert expert = jglExpertService.getOneById(jglExpert.getId());
                List<JglExpertResearchArea> areaList = expert.getJglExpertResearchAreaList();
//                专家里面是否存在 和植物相同的 四种类型
                boolean existEqual = areaList.stream().anyMatch(e -> jglPlant.allTypeEquals(e.getType1(), e.getType2(), e.getType3(), e.getType4()));
                if (!existEqual) {
                    Assert.isTrue(areaList.size() < 3, "专家擅长领域最多只能有三条");
                    areaList.add(new JglExpertResearchArea(expert.getId(), jglPlant.getType1(), jglPlant.getType2(), jglPlant.getType3(), jglPlant.getType4()));
                    expert.setJglExpertResearchAreaList(areaList);
                    jglExpertService.updateOne(expert);
                }
                jglPlantRefExpertList.add(new JglPlantRefExpert(jglExpert.getId(), jglPlant.getId()));
            }
        }
        if (ObjectUtils.isNotEmpty(jglPlantRefExpertList)) {
            jglPlantRefExpertDao.insertBatch(jglPlantRefExpertList);
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean updateOne(JglPlant jglPlant) {
        commonService.setModifyInfo(jglPlant);
        jglPlant.setTenantId(linkappUserContextProducer.getNotNullCurrent().getTenantId());
        validRepeat(jglPlant);
        validParamFormat(jglPlant);
        boolean r = updateById(jglPlant);
//        删除原有的 植物-专家 关联
        QueryWrapper<JglPlantRefExpert> qw = new QueryWrapper<>();
        qw.eq("plant_id", jglPlant.getId());
        jglPlantRefExpertDao.delete(qw);
        updateExpertResearchAreaAndUpdatePlantRefExpert(jglPlant);
        return r;
    }

    @Override
    public IPage<JglPlant> selectPage(Page<JglPlant> page, JglPlant jglPlant) {
        jglPlant.setTenantId(linkappUserContextProducer.getNotNullCurrent().getTenantId());
        long start = (page.getCurrent() - 1) * page.getSize();
        start = start < 0 ? 0 : start;
        List<JglPlant> records = baseMapper.getPageList(start, page.getSize(), jglPlant);
        IPage<JglPlant> r = new Page<>();
        r.setRecords(records);
        r.setCurrent(page.getCurrent());
        r.setSize(r.getRecords().size());
        r.setTotal(baseMapper.getPageCount(jglPlant));
        return r;
    }

    @Override
    public JglPlant getOneById(Serializable id) {
        return baseMapper.getOneById(id);
    }

    @Override
    public boolean deleteByIds(List<Long> idList) {
        Assert.notEmpty(idList, "id为空");
//        解绑植物与专家的关联关系
        QueryWrapper<JglPlantRefExpert> qw = new QueryWrapper<>();
        qw.in("plant_id", idList);
        jglPlantRefExpertService.remove(qw);
        return removeByIds(idList);
    }

    @Override
    public void export(JglPlant jglPlant, HttpServletRequest request, HttpServletResponse response) {
        IPage<JglPlant> page = selectPage(new Page<>(0, -1), jglPlant);
        List<JglPlant> records = page.getRecords();
        List<JglPlantVo> jglExpertVos = new ArrayList<>();
        for (JglPlant plant : records) {
            jglExpertVos.add(new JglPlantVo(plant));
        }
        String keyValue = "名称:name,形态特征:feature,分类:classification," +
                "分布:area";
        String title = "植物列表导出数据";
        String fileName = title + ".xls";
        try {
            OutputStream outputStream = OutputStreamUtil
                    .getOutputStream(request, response, fileName);
            ExcelTools.exportExcel(outputStream, keyValue, jglExpertVos, ExcelConstant.XLS, title);
            response.flushBuffer();
            outputStream.close();
        } catch (IOException e) {
            log.error("excel导出失败", e);
            throw new RuntimeException("excel导出失败！IOException异常" + e.getMessage());
        } catch (Exception e) {
            log.error("excel导出失败", e);
            throw new RuntimeException("excel导出失败！" + e.getMessage());
        }
    }


    /**
     * 校验重复
     */
    private void validRepeat(JglPlant jglPlant) {
        QueryWrapper<JglPlant> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("name", jglPlant.getName());
        queryWrapper.eq("tenant_id", linkappUserContextProducer.getNotNullCurrent().getTenantId());
        List<JglPlant> list = baseMapper.selectList(queryWrapper);
        if (list.size() == 0) {
            return;
        }
        if (list.size() > 1) {
            throw new BusinessException("植物名称有重复");
        }
        if (ObjectUtils.isEmpty(jglPlant.getId())) {
            throw new BusinessException("植物名称已存在");
        }
        if (!jglPlant.getId().equals(list.get(0).getId())) {
            throw new BusinessException("植物名称已存在");
        }

    }


    /**
     * 校验参数必填
     */
    private void validParamRequired(JglPlant jglPlant) {

        Assert.notNull(jglPlant, "参数为空");
        Assert.isTrue(StringUtils.isNotBlank(jglPlant.getName()), "名称为空");
        Assert.isTrue(StringUtils.isNotBlank(jglPlant.getTenantId()), "租户id为空");
    }

    /**
     * 校验参数格式
     */
    private void validParamFormat(JglPlant jglPlant) {
        Assert.isTrue(jglPlant.getName() == null || jglPlant.getName().length() <= 50, "植物名称超长");
        Assert.isTrue(jglPlant.getFeature() == null || jglPlant.getFeature().length() <= 2048, "植物特性超长");
        Assert.isTrue(jglPlant.getArea() == null || jglPlant.getArea().length() <= 1024, "植物分布范围超长");
        Assert.isTrue(jglPlant.getAttachment() == null || jglPlant.getAttachment().length() <= 1024, "植物附件超长");
    }
}

